// 定义常量，为了复用，且代码提示
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
    // promise内部状态
    status = PENDING;
    // 成功回调的返回值
    value = undefined;
    // 失败回调的原因
    reason = undefined;
    // 成功回调，then可以链式调用，所以定义为数组
    successCallback = []; // 
    // 失败回调，then可以链式调用，所以定义为数组
    failCallback = [];
    // 创建promise要传入回调函数，参数为成功回调和失败回调
    constructor(fn){
        // 捕获错误
        try{
            fn(this.resolve, this.reject)
        } catch(e) {
            this.reject(e)
        }
    }
    // resolve作用为把状态改为成功
    // 箭头函数，保证传递的返回值指向构造器本身
    resolve = value => {
        // 如果状态不是等待，阻止向下执行
        if(this.status !== PENDING) return
        // 状态改为成功
        this.status = FULFILLED
        // 保存修改后的值
        this.value = value
        // 循环调用所有回调函数
        while(this.successCallback.length){
            this.successCallback.shift()(this.value)
        }
    }
    reject = reason => {
        // 如果状态不是等待，阻止向下执行
        if(this.status !== PENDING) return
        // 状态改为成功
        this.status = FULFILLED
        // 保存修改后的值
        this.reason = reason
        // 循环调用所有回调函数
        while(this.failCallback.length){
            this.failCallback.shift()(this.reason)
        }
    }
    then(successCallback, fillCallback){

        let promise2 = new myPromise((resolve, reject) => {
            // 判断状态
            if(this.status == FULFILLED){
                setTimeout(()=>{
                    try {
                        let x = successCallback(this.value)
                        // 判断x的值时普通值，还是promise对象
                        // 如果是普通纸，直接调用resolve
                        // 如果是promise对象，查看promise对象返回的结果
                        // 再根据promise对象返回的结果，决定调用resolve 还是调用reject
                        resolvePromise(promise2, x, resolve, reject)
                    } catch(e){
                        reject(e)
                    }
                },0)
            }else if(this.status == REJECTED){
                setTimeout(()=>{
                    try {
                        let x = failCallback(this.reason)
                        // 判断x的值时普通值，还是promise对象
                        // 如果是普通纸，直接调用resolve
                        // 如果是promise对象，查看promise对象返回的结果
                        // 再根据promise对象返回的结果，决定调用resolve 还是调用reject
                        resolvePromise(promise2, x, resolve, reject)
                    }catch(e){
                        reject(e)
                    }
                },0)
            }else{
                // 等待的状态
                // 将成功回调和失败回调存储起来
                this.successCallback.push(() => {successCallback})
                this.failCallback.push(() => {failCallback})
            }
        });
        return promise2
    }
    static all(array){
        // 要判断数组中的的值时普通值还是promise对象，如果普通值，直接放入结果数组中
        let result = []
        let index = 0;
        return new myPromise((resolve, reject)=>{
            function addData(key, value){
                result[key] = value
                index++
                if(index === array.length){
                    resolve(result)
                }
            }
            for(let i = 0; i < array.length; i++){
                let current = array[i]
                if(current instanceof myPromise){
                    // promise对象
                    current.then(value => {
                        addData(i, value)
                    }, (reason) => {
                        reject(reason)
                    })
                }else{
                    // 普通值
                    addData(i, array[i])
                }
            }
        })
    }
    static resolve(val){
        if(val instanceof myPromise){
            return val
        }else{
            return new myPromise(resolve => {
                resolve(val)
            })
        }
    }
    finally(callback){
        return this.then(value =>{
            // 返回的promise对象如果内部有异步操作，让后面的then等待执行完成
            // then可以等待异步执行
            return myPromise.resolve(callback())
                .then(()=> value)
        }, reason =>{
            return myPromise
                .resolve(callback())
                .then(()=> {throw reason})
        })
    }
    static race(arr){
        return new MyPromise((resolve, reject) => {
            let i = 0;
            // 循环执行异步操作，只要出现resolve或reject就会将返回的promise对象状态进行修改
            while(i < arr.length){
                arr[i].then(res => {
                    resolve(res) 
                }).catch(error => {
                    reject(error)
                })
            }
        })
    }
}
function resolvePromise(promise2, x, resolve, reject){
    // 如果then内返回自身，抛出异常
    if(promise2 === x){
        // return 阻止程序向下执行
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if(x instanceof MyPromise){
        // promise对象
        x.then(resolve, reject)
    }else{
        // 普通值
        resolve(x)
    }
}
